/********************************************************************************
* Project       : No Latency RTSP streaming Project
* Author        : Seo, SeokWon 
* e-mail        : kueony@gmail.com
* Licence       : See the Copyright
*********************************************************************************/


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>

#include "lib_log.h"

// define
#if LIB_LOG_MODE_FILE
	#define	LIB_LOG_FILENAME	"data.log"
	#define LIB_LOG_LINE_MAX	1024 * 1000 * 5
#endif

#define LIB_LOG_TAG_MSG		"[MSG  ]"
#define LIB_LOG_TAG_ERROR	"[ERR  ]"
#define LIB_LOG_TAG_DATA	"[DATA ]"
#define LIB_LOG_TAG_DEBUG	"[DEBUG]"

// variables
static char	g_caLogFileName[256] = {0, };
static int	g_iLogFd = 0xffffffff;
static int	g_iTypeFlag = 0;

// functions
#if LIB_LOG_MODE_FILE
	static int	LibLogInit();
	static int	LibLogFileBackup();
#endif


// ...............................................................

int LibLogSetFileName(char *a_pcFileName)
{
	if(strlen(a_pcFileName) < 1) return -1;
	
	bzero(g_caLogFileName, sizeof(g_caLogFileName));

	sprintf(g_caLogFileName, "%.256s", a_pcFileName);

	return 0;
}


void LibLogSetType(int a_iFlag)
{
	g_iTypeFlag = a_iFlag;

	return;
}


#if LIB_LOG_MODE_FILE
static int LibLogInit()
{
	if(strlen(g_caLogFileName) < 1)
	{
		g_iLogFd = open(LIB_LOG_FILENAME, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, 0644);
		sprintf(g_caLogFileName, "%.256s", LIB_LOG_FILENAME);
	}
	else
	{
		g_iLogFd = open(g_caLogFileName, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, 0644);
	}

	if(g_iLogFd < 0)
	{
		perror("log_file");
		return -1;
	}
	
	return 0;
}
#endif


#if LIB_LOG_MODE_FILE
static int LibLogFileBackup()
{
	char		caBuf[1024] = {0, };
	time_t		tNowTime;
	struct tm*	stTime;

	sprintf(caBuf, "cp -rf %s %s.backup", g_caLogFileName, g_caLogFileName);
	system(caBuf);

	ftruncate(g_iLogFd, 0);
	
	bzero(caBuf, sizeof(caBuf));
	time(&tNowTime);
	stTime = localtime(&tNowTime);
	sprintf(caBuf, "[%04d:%02d:%02d-%02d:%02d:%02d] <log backup complete & reload>\n", stTime->tm_year + 1900, stTime->tm_mon + 1, stTime->tm_mday,
															stTime->tm_hour, stTime->tm_min, stTime->tm_sec);

	lseek(g_iLogFd, 0, SEEK_SET);
	write(g_iLogFd, caBuf, strlen(caBuf));

	return 0;
}
#endif


#if LIB_LOG_MODE_PRINT
void LibLogPrint(int a_iType, const char *a_pcncFormat, ...)
{
	va_list vaList;	

	if((g_iTypeFlag & a_iType) == 0) return;

	switch(a_iType)
	{
		case LIB_LOG_TYPE_MSG:
			fprintf(stdout, "%s ", LIB_LOG_TAG_MSG);
			break;
		case LIB_LOG_TYPE_ERROR:
			fprintf(stdout, "%s ", LIB_LOG_TAG_ERROR);
			break;
		case LIB_LOG_TYPE_DATA:
			fprintf(stdout, "%s ", LIB_LOG_TAG_DATA);
			break;
		case LIB_LOG_TYPE_DEBUG:
			fprintf(stdout, "%s ", LIB_LOG_TAG_DEBUG);
			break;
		default:
			return;
	}
	
	va_start(vaList, a_pcncFormat);
	vfprintf(stdout, a_pcncFormat, vaList);
	fprintf(stdout, "\n");
	va_end(vaList);

	return;
}
#endif


#if LIB_LOG_MODE_FILE
void LibLogFile(int a_iType, const char *a_pcncFormat, ...)
{
	va_list		vaList;	
	char		caTime[64] = {0, };
	char		caLogMsg[512] = {0, };
	char		caWriteBuf[1024] = {0, };
	time_t		tNowTime;
	struct tm*	stTime;

	if((g_iTypeFlag & a_iType) == 0) return;

	time(&tNowTime);
	stTime = localtime(&tNowTime);
	sprintf(caTime, "[%04d:%02d:%02d-%02d:%02d:%02d]", stTime->tm_year + 1900, stTime->tm_mon + 1, stTime->tm_mday,
															stTime->tm_hour, stTime->tm_min, stTime->tm_sec);

	va_start(vaList, a_pcncFormat);
	vsprintf(caLogMsg, a_pcncFormat, vaList);
	va_end(vaList);

	switch(a_iType)
	{
		case LIB_LOG_TYPE_MSG:
			sprintf(caWriteBuf, "%.64s %.7s %.256s\n", caTime, LIB_LOG_TAG_MSG, caLogMsg);
			break;
		case LIB_LOG_TYPE_ERROR:
			sprintf(caWriteBuf, "%.64s %.7s %.256s\n", caTime, LIB_LOG_TAG_ERROR, caLogMsg);
			break;
		case LIB_LOG_TYPE_DATA:
			sprintf(caWriteBuf, "%.64s %.7s %.256s\n", caTime, LIB_LOG_TAG_DATA, caLogMsg);
			break;
		case LIB_LOG_TYPE_DEBUG:
			sprintf(caWriteBuf, "%.64s %.7s %.256s\n", caTime, LIB_LOG_TAG_DEBUG, caLogMsg);
			break;
		default:
			return;
			break;
	}

	if(access(g_caLogFileName, R_OK) != 0 || g_iLogFd < 3)
	{
		close(g_iLogFd);

		if(LibLogInit() == 0) write(g_iLogFd, caWriteBuf, strlen(caWriteBuf));
	}
	else
	{
		if(write(g_iLogFd, caWriteBuf, strlen(caWriteBuf)) < 0)
		{
			if(errno == EBADF || errno == EAGAIN)
			{
				if(LibLogInit() == 0) write(g_iLogFd, caWriteBuf, strlen(caWriteBuf));
			}
		}
	}

	if(lseek(g_iLogFd, 0, SEEK_CUR) > LIB_LOG_LINE_MAX) LibLogFileBackup(); 
	
	return;
}
#endif


void LibLogQuit()
{
	close(g_iLogFd);

	return;
}
